home *** CD-ROM | disk | FTP | other *** search
/ AmigActive 26 / AACD 26.iso / AACD / Programming / ace_gpl_release / src_ansi / ace / c / opt.c < prev    next >
Encoding:
C/C++ Source or Header  |  1999-01-05  |  7.9 KB  |  340 lines

  1. /* << ACE >>
  2.  
  3.    -- Amiga BASIC Compiler --
  4.  
  5.    ** Optimiser **
  6.    ** Copyright (C) 1998 David Benn
  7.    ** 
  8.    ** This program is free software; you can redistribute it and/or
  9.    ** modify it under the terms of the GNU General Public License
  10.    ** as published by the Free Software Foundation; either version 2
  11.    ** of the License, or (at your option) any later version.
  12.    **
  13.    ** This program is distributed in the hope that it will be useful,
  14.    ** but WITHOUT ANY WARRANTY; without even the implied warranty of
  15.    ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  16.    ** GNU General Public License for more details.
  17.    **
  18.    ** You should have received a copy of the GNU General Public License
  19.    ** along with this program; if not, write to the Free Software
  20.    ** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
  21.  
  22.    Author: David J Benn
  23.    Date: 8th,9th,11th,14th June 1992,
  24.    2nd,5th July 1992,
  25.    6th December 1992,
  26.    25th December 1993,
  27.    5th,9th-11th April 1994,
  28.    24th July 1994,
  29.    11th September 1994,
  30.    11th March 1995
  31.  */
  32.  
  33. #include "acedef.h"
  34. #include <string.h>
  35.  
  36. /* globals */
  37. CODE *curr, *first, *second;
  38. char opcode[40], srcopr[40], destopr[40];
  39. SHORT peep = 0;
  40.  
  41. /* externals */
  42. extern CODE *code;
  43.  
  44. /* functions */
  45. BOOL is_a_move (char *opcode)
  46. {
  47.   if (opcode[0] == 'm')
  48.     {
  49.       if (strcmp (opcode, "move.b") == 0)
  50.     return (TRUE);
  51.       else if (strcmp (opcode, "move.w") == 0)
  52.     return (TRUE);
  53.       else if (strcmp (opcode, "move.l") == 0)
  54.     return (TRUE);
  55.       else
  56.     return (FALSE);
  57.     }
  58.   else
  59.     return (FALSE);
  60. }
  61.  
  62. BOOL push_pop_pair (void)
  63. {
  64. /* 
  65.    ** Eliminate:        stack push/pop pair
  66.    **           eg: move.l d0,-(sp)
  67.    **                       move.l (sp)+,d1     ->      move.l d0,d1            [A]
  68.    **
  69.    **      OR
  70.    ** 
  71.    **           redundant dest/src register pair (from other optimisations) 
  72.    **           eg: move.l #3,d0
  73.    **               move.l d0,-4(a4)    ->      move.l #3,-4(a4)        [B]
  74.    **
  75.    **           Don't apply this transformation to instructions which
  76.    **           use labelled (BSS/DATA) items since ACE (esp. in gfx.c)
  77.    **           does things with such items which if optimised can lead
  78.    **           to a loss of valid code (eg. a d0 move may be eliminated
  79.    **           when it is required for a shared library function call;
  80.    **           see the code for COLOR as an example). This should only
  81.    **           be a problem for case [B] above, not case [A] since no
  82.    **           registers are removed in [A].
  83.  */
  84.  
  85.   if (strcmp (first->opcode, second->opcode) == 0 &&
  86.       is_a_move (first->opcode)
  87.  
  88.       &&
  89.  
  90.       ((strcmp (first->destopr, "-(sp)") == 0 &&
  91.     strcmp (second->srcopr, "(sp)+") == 0)    /* [A] */
  92.  
  93.        ||
  94.  
  95.        (strcmp (first->destopr, "d0") == 0 &&
  96.     strcmp (second->srcopr, "d0") == 0 &&
  97.     first->srcopr[0] != '_' &&
  98.     second->destopr[0] != '_')))    /* [B] */
  99.     {
  100.       /* copy required code */
  101.       strcpy (opcode, first->opcode);
  102.       strcpy (srcopr, first->srcopr);
  103.       strcpy (destopr, second->destopr);
  104.  
  105.       /* modify first line */
  106.       if (strcmp (srcopr, destopr) != 0)
  107.     change (first, opcode, srcopr, destopr);    /* src operand != dest operand */
  108.       else
  109.     {
  110.       /* 
  111.          ** src operand == dest operand 
  112.          **
  113.          ** eg.         move.l d0,-(sp)
  114.          **     move.l (sp)+,d0
  115.          **
  116.          **     =  move.l d0,d0       [elimimate this!]
  117.        */
  118.       change (first, "nop", "  ", "  ");
  119.       peep++;
  120.     }
  121.  
  122.       /* eliminate second line */
  123.       change (second, "nop", "  ", "  ");
  124.  
  125.       /* skip second line */
  126.       curr = second->next;
  127.  
  128.       peep++;
  129.  
  130.       return (TRUE);
  131.     }
  132.   else
  133.     return (FALSE);
  134. }
  135.  
  136. BOOL sign_bit_extension (void)
  137. {
  138. /*
  139.    ** Combine:  move.b #n,dm
  140.    **           ext.w  dm
  141.    **
  142.    **      ->   move.w #n,dm
  143.    **
  144.    **      OR
  145.    **           move.w #n,dm
  146.    **           ext.l  dm
  147.    **
  148.    **      ->   move.l #n,dm
  149.    **
  150.    **
  151.    **     NOT   move.w (sp)+,dm
  152.    **           ext.l  dm
  153.    **
  154.    **           since this would change a short pop into a long pop!
  155.    **
  156.    **     NOR   move.w _mylabel,dm
  157.    **           ext.l  dm
  158.    **
  159.    **           since this would try to move data beyond the confines
  160.    **           of the BSS/DATA block starting from _mylabel. 
  161.    **
  162.    **    In short, this technique is only useful for immediate mode 
  163.    **    addressed operands.
  164.    **
  165.    **    Note that this kind of optimisation may lead to redundant register 
  166.    **    moves (eg. compile the 2 line program: 'DEFLNG a-z / X = 1' and
  167.    **    work through the transformations), so push_pop_pair() should be
  168.    **    called after this function.
  169.  */
  170.  
  171.   if (strcmp (second->opcode, "ext.l") == 0 &&
  172.       strcmp (first->opcode, "move.w") == 0 &&
  173.       first->srcopr[0] == '#')
  174.     {
  175.       strcpy (opcode, "move.l");
  176.       strcpy (srcopr, first->srcopr);
  177.       strcpy (destopr, first->destopr);
  178.       change (first, opcode, srcopr, destopr);
  179.       change (second, "nop", "  ", "  ");
  180.       curr = second->next;
  181.       peep++;
  182.       return (TRUE);
  183.     }
  184.   else if (strcmp (second->opcode, "ext.w") == 0 &&
  185.        strcmp (first->opcode, "move.b") == 0 &&
  186.        first->srcopr[0] == '#')
  187.     {
  188.       strcpy (opcode, "move.w");
  189.       strcpy (srcopr, first->srcopr);
  190.       strcpy (destopr, first->destopr);
  191.       change (first, opcode, srcopr, destopr);
  192.       change (second, "nop", "  ", "  ");
  193.       curr = second->next;
  194.       peep++;
  195.       return (TRUE);
  196.     }
  197.   else
  198.     return (FALSE);
  199. }
  200.  
  201. BOOL negate_constant (void)
  202. {
  203. /*
  204.    ** Constant Negation:        move.w #n,-(sp)
  205.    **                   neg.w  (sp)
  206.    **                   move.w (sp)+,d0         
  207.    **   becomes:        
  208.    **                   move.w #-n,-(sp)
  209.    **                   move.w(sp)+,d0
  210.    **
  211.    **   The latter is then a candidate for removal by push_pop_pair().  
  212.  */
  213.  
  214.   if (((strcmp (second->opcode, "neg.w") == 0 &&
  215.     strcmp (first->opcode, "move.w") == 0) ||
  216.  
  217.        (strcmp (second->opcode, "neg.l") == 0 &&
  218.     strcmp (first->opcode, "move.l") == 0)) &&
  219.  
  220.       first->srcopr[0] == '#')
  221.     {
  222.       strcpy (opcode, first->opcode);
  223.       srcopr[0] = '#';
  224.  
  225.       if (first->srcopr[1] != '-')
  226.     {
  227.       /*
  228.          ** Constant is not negative so negate it.
  229.        */
  230.       srcopr[1] = '-';
  231.       srcopr[2] = '\0';
  232.       strcat (srcopr, &first->srcopr[1]);
  233.     }
  234.       else
  235.     {
  236.       /*
  237.          ** Constant is negative so skip '-'.
  238.        */
  239.       srcopr[1] = '\0';
  240.       strcat (srcopr, &first->srcopr[2]);
  241.     }
  242.  
  243.       strcpy (destopr, first->destopr);
  244.       change (first, opcode, srcopr, destopr);
  245.       change (second, "nop", "  ", "  ");
  246.       curr = second->next;
  247.       peep++;
  248.       return (TRUE);
  249.     }
  250.   else
  251.     return (FALSE);
  252. }
  253.  
  254. SHORT peephole (void)
  255. {
  256. /* 
  257.    ** Perform a series of peephole 
  258.    ** optimisations on the code list.
  259.  */
  260.   BOOL past_head;
  261.   int opt_type;
  262.  
  263.   if (code == NULL)
  264.     return (0);
  265.  
  266.   for (opt_type = 1; opt_type <= 4; opt_type++)
  267.     {
  268.       /* Start of code list */
  269.       curr = code;
  270.  
  271.       past_head = FALSE;
  272.  
  273.       do
  274.     {
  275.       /* get next two lines of code (skipping nops) */
  276.       first = curr;
  277.       if (first != NULL)
  278.         {
  279.           second = first->next;
  280.  
  281.           while (second && strcmp (second->opcode, "nop") == 0)
  282.         second = second->next;
  283.  
  284.           curr = second;
  285.         }
  286.       else
  287.         {
  288.           curr = second = NULL;
  289.         }
  290.  
  291.       /* 
  292.          ** Remove redundant code in current peephole.
  293.          **
  294.          ** Only do this if we're past the head of the
  295.          ** code list but haven't yet reached the end of 
  296.          ** this list.
  297.        */
  298.       if (past_head && second != NULL)
  299.         switch (opt_type)
  300.           {
  301.           case 1:
  302.         negate_constant ();
  303.         break;
  304.  
  305.           case 2:
  306.         push_pop_pair ();
  307.         break;
  308.  
  309.           case 3:
  310.         sign_bit_extension ();
  311.         break;
  312.  
  313.           case 4:
  314.         push_pop_pair ();
  315.         break;
  316.           }
  317.  
  318.       if (!past_head)
  319.         past_head = TRUE;
  320.     }
  321.       while (curr != NULL);
  322.     }
  323.  
  324.   /* total # of removals */
  325.   return (peep);
  326. }
  327.  
  328. void optimise (void)
  329. {
  330.   SHORT opeep;
  331.  
  332.   printf ("\noptimising...\n");
  333.   opeep = peephole ();
  334.   printf ("%d peephole ", opeep);
  335.   if (opeep == 1)
  336.     printf ("removal.");
  337.   else
  338.     printf ("removals.");    /* opeep==0 or opeep>1 */
  339. }
  340.